parser grammar CodigoCParser;

options {
  language = Java;
  tokenVocab = CodigoCLexer;
  backtrack = true;
}

@header {
  package practica8;
  import java.util.Hashtable;
}

@members {

    int bloque = 0;
    String tabulacion = "   ";
    String n_tab = "";
    
    private ArrayList<RecognitionException> errors = new ArrayList<RecognitionException>();
    public ArrayList<RecognitionException> getErrors() {
       return errors;
    }
    @Override
    public void reportError (RecognitionException e) {
       String msg = getErrorMessage(e, getTokenNames());
       System.err.println(msg);
       errors.add(e);
    }
}



entrada returns [String salida = ""]: p=principal {salida += p;};


//Main
principal returns [String salida = ""]: v=VOID m=MAIN p=parametros b=bloque {salida += v.getText() + " " + m.getText() + p + b;};


//Parametros del main
parametros returns [String salida = ""]: pa=PARENTESIS_A {salida += pa.getText();} (v=VOID {salida += v.getText();})? pc=PARENTESIS_C {salida += pc.getText() + " ";}
                                         |
                                         pa=PARENTESIS_A t=tipo p=parametro {salida += pa.getText() + t + p;} (c=COMA tt=tipo  pp=parametro {salida += c.getText() + " " + tt + pp;})* pc=PARENTESIS_C {salida += pc.getText() + " ";};

//Tipos de datos
tipo returns [String salida = ""]: i=INT {salida += i.getText();}
                                   |
                                   c=CHAR {salida += c.getText();}
                                   |
                                   v=VOID {salida += v.getText();};

//Parametros de una funcion
parametro returns [String salida = ""]: i=IDENT {salida += i.getText();} | n=NUMERO {salida += n.getText();};

//Bloque de una funcion, bucle...
bloque returns [String salida = ""]: la=LLAVE_A {salida += la.getText() + '\n'; n_tab += tabulacion;} (s=sentencias {salida += n_tab + s;})* lc=LLAVE_C {n_tab = n_tab.substring(0, n_tab.length()-3); salida += n_tab + lc.getText() + '\n';};

//Sentencias que pueden realizarse
sentencias returns [String salida = ""]: bw=bucle_while {salida += bw;} | ci=condicional_if {salida += ci;} | s=salir {salida += s;} | d=declaracion {salida += d;} | i=imprimir {salida += i;} | a=asignacion {salida += a;};

//Bucle while
bucle_while returns [String salida = ""]: w=WHILE c=condicion b=bloque {salida += w.getText() + c + b;};

//Condicional if
condicional_if returns [String salida = ""]: i=IF c=condicion b=bloque {salida += i.getText() + c + b;};

//Condicion para while o if
condicion returns [String salida = ""]: pa=PARENTESIS_A {salida += pa.getText();} (i=IDENT {salida += i.getText();} | c=comparacion {salida += c;}) pc=PARENTESIS_C {salida += pc.getText() + " ";};

//Comparacion de una condicion
comparacion returns [String salida = ""]: e1=expr c=COMPARADOR e2=expr {salida += e1 + c.getText() + e2;};

//Expresion matematica
expr returns [String salida = ""]: (r=RESTA {salida += r.getText();})? (n=NUMERO {salida += n.getText();} |i=IDENT {salida += i.getText();}) (o=operador {salida += o;} (rr=RESTA {salida += rr.getText();})? (n=NUMERO {salida += n.getText();} |i=IDENT {salida += i.getText();}))*;

//Operadores aritmeticos
operador returns [String salida = ""]: s=SUMA {salida += s.getText();}
                                       |
                                       r=RESTA {salida += r.getText();}
                                       |
                                       m=MULT {salida += m.getText();}
                                       |
                                       d=DIV {salida += d.getText();};

//Sentencia break
salir returns [String salida = ""]: b=BREAK pc=PUNTO_COMA {salida += b.getText() + pc.getText() + '\n';};

//Declaracion de variables
declaracion returns [String salida = ""]: t=tipo {salida += t + " ";} i=IDENT {salida += i.getText();} (c=COMA {salida += c.getText() + " ";} ii=IDENT {salida += ii.getText();})* pc=PUNTO_COMA {salida += pc.getText() + '\n';};

//Sentencia printf
imprimir returns [String salida = ""]: p=PRINTF pa=PARENTESIS_A c=CADENA {salida += p.getText() + pa.getText() + c.getText();} (cm=COMA i=IDENT {salida += cm.getText() + " " + i.getText();})* pc=PARENTESIS_C pyc=PUNTO_COMA {salida += pc.getText() + pyc.getText() + '\n';};

//Asignacion de variable
asignacion returns [String salida = ""]: i=IDENT ig=IGUAL {salida += i.getText() + ig.getText();} (e=expr {salida += e;} | n=NUMERO {salida += n.getText();}) pyc=PUNTO_COMA {salida += pyc.getText() + '\n';};